//
//  TCSegment.swift
//  TCSegment
//
//  Created by 叮叮 on 2021/4/13.
//

import UIKit

@objc protocol TCSegmentDelegate {
    @objc optional
    func segmentDidSelected(index: Int, segment: UIButton)
}

class TCSegment: UIView {
    
    static var titleColor: UIColor = UIColor.black
    static var selectedTitleColor: UIColor = UIColor.black
    static var titleFont: UIFont = UIFont.systemFont(ofSize: 17)
    static var backgroundColor: UIColor = UIColor.systemGray4
    static var cornerRadius: CGFloat = 8
    static var indicatorColor: UIColor = UIColor.white
    static var buttonMargin: UIEdgeInsets  = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
    
    var segments: Array<String>
    private var segmentButtons: Array<UIButton> = []
    private let indicator: UIView = UIView()
    private let indicatorContentView: UIView = UIView()
    private var selectedSegmentButton: UIButton?
    private var buttonMargin: UIEdgeInsets {
        get {
            return Self.buttonMargin
        }
    }
    var delegate: TCSegmentDelegate?
    
    init(segments: Array<String> = [], frame: CGRect = CGRect.zero) {
        self.segments = segments
        super.init(frame: frame)
        translatesAutoresizingMaskIntoConstraints = false
        clipsToBounds = true
        setupUI()
    }
    
    func setupUI() {
        let backgroundView = UIView()
        backgroundView.layer.backgroundColor = Self.backgroundColor.cgColor
        backgroundView.layer.cornerRadius = Self.cornerRadius
        backgroundView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(backgroundView)
        
        let top = NSLayoutConstraint(item: backgroundView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0)
        let left = NSLayoutConstraint(item: backgroundView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 0)
        let right = NSLayoutConstraint(item: backgroundView, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1, constant: 0)
        let bottom = NSLayoutConstraint(item: backgroundView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
        addConstraint(top)
        addConstraint(left)
        addConstraint(right)
        addConstraint(bottom)
        
        addSubview(indicator)
        
        indicatorContentView.layer.backgroundColor = Self.indicatorColor.cgColor
        indicatorContentView.layer.shadowColor = UIColor.black.cgColor
        indicatorContentView.layer.shadowOpacity = 0.2
        indicatorContentView.layer.shadowOffset = .zero
        indicatorContentView.layer.shadowRadius = 5
        indicator.addSubview(indicatorContentView)
        
        segments.enumerated().forEach { (index, title) in
            let segmentButton = UIButton(type: .custom)
            segmentButton.translatesAutoresizingMaskIntoConstraints = false
            segmentButton.setTitle(title, for: .normal)
            segmentButton.setTitleColor(Self.titleColor, for: .normal)
            segmentButton.titleLabel?.font = Self.titleFont
            segmentButton.addTarget(self, action: #selector(segmentButtonAction(sender:)), for: .touchUpInside)
            segmentButton.addTarget(self, action: #selector(segmentButtonTouchDown(sender:)), for: .touchDown)
            segmentButton.addTarget(self, action: #selector(segmentButtonDragOut(sender:)), for: .touchUpOutside)
            segmentButton.index = index
            addSubview(segmentButton)
            segmentButtons.append(segmentButton)
        }
        
        selectedSegmentButton = segmentButtons.first
        
        segmentButtons.enumerated().forEach { (index, button) in
            
            guard index != 0 else {
                button.setTitleColor(Self.selectedTitleColor, for: .normal)
                
                let nextButton = segmentButtons[index + 1]
                
                let top = NSLayoutConstraint(item: button, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0)
                let left = NSLayoutConstraint(item: button, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 0)
                let right = NSLayoutConstraint(item: button, attribute: .right, relatedBy: .equal, toItem: nextButton, attribute: .left, multiplier: 1, constant: 0)
                let bottom = NSLayoutConstraint(item: button, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
                let width = NSLayoutConstraint(item: button, attribute: .width, relatedBy: .equal, toItem: nextButton, attribute: .width, multiplier: 1, constant: 0)
                addConstraint(top)
                addConstraint(left)
                addConstraint(right)
                addConstraint(bottom)
                addConstraint(width)
                return
            }
            
            guard index != segmentButtons.count - 1 else {
                
                let previousButton = segmentButtons[index - 1]
                
                let top = NSLayoutConstraint(item: button, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0)
                let left = NSLayoutConstraint(item: button, attribute: .left, relatedBy: .equal, toItem: previousButton, attribute: .right, multiplier: 1, constant: 0)
                let right = NSLayoutConstraint(item: button, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1, constant: 0)
                let bottom = NSLayoutConstraint(item: button, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
                let width = NSLayoutConstraint(item: button, attribute: .width, relatedBy: .equal, toItem: previousButton, attribute: .width, multiplier: 1, constant: 0)
                addConstraint(top)
                addConstraint(left)
                addConstraint(right)
                addConstraint(bottom)
                addConstraint(width)
                return
            }
            
            let previousButton = segmentButtons[index - 1]
            let nextButton = segmentButtons[index + 1]
            
            let top = NSLayoutConstraint(item: button, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0)
            let left = NSLayoutConstraint(item: button, attribute: .left, relatedBy: .equal, toItem: previousButton, attribute: .right, multiplier: 1, constant: 0)
            let right = NSLayoutConstraint(item: button, attribute: .right, relatedBy: .equal, toItem: nextButton, attribute: .left, multiplier: 1, constant: 0)
            let bottom = NSLayoutConstraint(item: button, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
            let width = NSLayoutConstraint(item: button, attribute: .width, relatedBy: .equal, toItem: previousButton, attribute: .width, multiplier: 1, constant: 0)
            addConstraint(top)
            addConstraint(left)
            addConstraint(right)
            addConstraint(bottom)
            addConstraint(width)
        }
    }
    
    @objc func segmentButtonAction(sender: UIButton) {
        if (selectedSegmentButton == sender) {
            UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 1, options: .curveEaseInOut) { [self] in
                indicatorContentView.transform = .identity
            }
            return
        }
        selectedSegmentButton?.setTitleColor(Self.titleColor, for: .normal)
        sender.setTitleColor(Self.selectedTitleColor, for: .normal)
        selectedSegmentButton = sender
        UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 1, options: .curveEaseInOut) { [self] in
            indicator.frame = sender.frame
        }
        delegate?.segmentDidSelected?(index: sender.index, segment: sender)
    }
    
    @objc func segmentButtonTouchDown(sender: UIButton) {
        if (selectedSegmentButton == sender) {
            UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseIn) { [self] in
                indicatorContentView.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
            }
            return
        }
    }
    
    @objc func segmentButtonDragOut(sender: UIButton) {
        if (selectedSegmentButton == sender) {
            UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 1, options: .curveEaseInOut) { [self] in
                indicatorContentView.transform = .identity
            }
            return
        }
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        if let button = selectedSegmentButton {
            let cornerRadiusRatio = button.bounds.size.height / Self.cornerRadius
            indicator.frame = button.frame
            indicatorContentView.frame = CGRect(x: buttonMargin.left, y: buttonMargin.top, width: button.bounds.size.width - buttonMargin.left - buttonMargin.right, height: button.bounds.size.height - buttonMargin.top - buttonMargin.bottom)
            
            indicatorContentView.layer.cornerRadius = indicatorContentView.bounds.size.height / cornerRadiusRatio
        }
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension UIButton {
    private struct buttonKeys {
        static var index = "buttonIndex"
    }
     
    var index: Int {
        get {
            return objc_getAssociatedObject(self,&buttonKeys.index) as? Int ?? 0
        }
        set {
            objc_setAssociatedObject(self, &buttonKeys.index, newValue, .OBJC_ASSOCIATION_RETAIN)
        }
    }
}
